﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting;
using System.Collections;
using System.Runtime.Remoting.Channels;
using Valentia.Kinection.Remoting.Proxy;
using Valentia.Kinection.DataTypes;

namespace Valentia.Kinection.Remoting.ServerTest
{
    public class _RemotingServer // : MarshalByRefObject, IRemotingServerObject
    {

        /// <summary>
        /// Delegate for devices connection information to be sent.
        /// </summary>
        public delegate void CommandFromClientReceivedDlg(String command);

        /// <summary>
        /// This event will be fired when server needs to send information of devices connection to client.
        /// </summary>
        public event CommandFromClientReceivedDlg CommandFromClientReceived;

        #region Fields

        private TcpServerChannel serverChannel;
        private int tcpPort;
        private ObjRef internalRef;
        private bool serverActive = false;
        private static string serverURI = "serverExample.Rem";

        #endregion

        #region Public Methods

        public void StartServer()
        {
            if (serverActive)
                throw new Exception("Server Already Connected");

            Hashtable props = new Hashtable();
            props["port"] = 15000;
            props["name"] = serverURI;

            //Set up for remoting events properly
            BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();
            serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

            serverChannel = new TcpServerChannel(props, serverProv);

            try
            {
                ChannelServices.RegisterChannel(serverChannel, false);
                //internalRef = RemotingServices.Marshal(this, props["name"].ToString());
                serverActive = true;
            }
            catch (RemotingException re)
            {
                throw re;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void StopServer()
        {
            if (!serverActive)
                throw new Exception("Server Already Stopped");

            try
            {
                RemotingServices.Unmarshal(internalRef);
                ChannelServices.UnregisterChannel(serverChannel);

                serverActive = false;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #endregion

        #region IRemotingServerObject Members

        #region Events

        /// <summary>
        /// This event will be fired when server needs to send information of devices connected to service.
        /// </summary>
        public event DeviceConnectivityInfo KinectDeviceInfoReceived;

        /// <summary>
        /// This event will be fired when server needs to send information of client connected to service.
        /// </summary>
        public event ClientConnectivityInfo ServiceClientInfoReceived;

        #endregion

        #region Methods

        /// <summary>
        /// This method will be use to send command from client to server
        /// </summary>
        /// <param name="command">Command</param>
        public void CommandFromClient(String command)
        {
            if (CommandFromClientReceived != null)
            {
                CommandFromClientReceived(command);
            }
        }

        #endregion

        #endregion

        public void RaiseDeviceConnectivityInfoEventOnClient(List<KinectDeviceInfo> deviceConnectionInfo, String errorMessage)
        {
            if (!serverActive)
                return;

            if (KinectDeviceInfoReceived == null)
                return;         //No Listeners

            DeviceConnectivityInfo listener = null;
            Delegate[] dels = KinectDeviceInfoReceived.GetInvocationList();

            foreach (Delegate del in dels)
            {
                try
                {
                    listener = (DeviceConnectivityInfo)del;
                    listener.Invoke(deviceConnectionInfo, errorMessage);
                }
                catch (Exception ex)
                {
                    //Could not reach the destination, so remove it
                    //from the list
                    KinectDeviceInfoReceived -= listener;
                }
            }
        }

        public void RaiseClientConnectivityInfoEventOnClient(List<ServiceClientInfo> clientConnectionInfo, String errorMessage)
        {
            if (!serverActive)
                return;

            if (ServiceClientInfoReceived == null)
                return;         //No Listeners

            ClientConnectivityInfo listener = null;
            Delegate[] dels = ServiceClientInfoReceived.GetInvocationList();

            foreach (Delegate del in dels)
            {
                try
                {
                    listener = (ClientConnectivityInfo)del;
                    listener.Invoke(clientConnectionInfo, errorMessage);
                }
                catch (Exception ex)
                {
                    //Could not reach the destination, so remove it
                    //from the list
                    ServiceClientInfoReceived -= listener;
                }
            }
        }
    }
}